﻿using System;
using System.Collections.Generic;
using System.Linq;
using Me.Practice.ElevatorEngine.Configuration;
using System.Threading;
using Me.Practice.ElevatorEngine.Domain.Entity;

namespace Me.Practice.ElevatorEngine.Infrastructure
{
    public class FloorController
    {
        private volatile bool _interruptSignal;

        public FloorController(Floor floor)
        {
            ControlledFloor = floor;
        }

        public Floor ControlledFloor { get; private set; }

        private void AppearPerson()
        {
            int target;
            do
                target =
                    new Random().Next(BuildingContext.Floors.Count()); while (target == 0);

            ControlledFloor.Enqueue(new Person(new Person.Init
                                                   {
                                                       FirstName = "Unknown",
                                                       LastName = "Unknown",
                                                       TargetFloorNumber =
                                                           BuildingContext.Floors.Single(f => f.Number == target).Number
                                                   }));
        }

        public void Open()
        {
            while (!_interruptSignal)
            {
                AppearPerson();
                Thread.Sleep(1000);
            }
        }

        public void Close()
        {
            _interruptSignal = true;
        }

        public void OnElevatorArrived(ElevatorController controller, int toFloor)
        {
            if (toFloor == ControlledFloor.Number && ControlledFloor.HasQueuedPerson())
            {
                lock (controller.ControlledElevator.Persons)
                {
                    //
                    // Person out emulation.
                    //
                    var persons =
                        controller.ControlledElevator.Persons.Where(
                            p => p.TargetFloorNumber == controller.ControlledElevator.CurrentFloorNumber).ToArray();

                    foreach (var person in persons)
                    {
                        ((IList<Person>) controller.ControlledElevator.Persons).Remove(person);
                        Thread.Sleep(controller.ControlledElevator.Timeout*1000);
                    }
                }
            }

            //
            // Person enter emulation.
            //
            while (controller.ControlledElevator.Capacity > controller.ControlledElevator.Persons.Count() && ControlledFloor.HasQueuedPerson())
            {
                Person person;
                if (ControlledFloor.TryDequeue(out person))
                {
                    ((IList<Person>) controller.ControlledElevator.Persons).Add(person);
                    Thread.Sleep(controller.ControlledElevator.Timeout*1000);
                }
            }
        }
    }
}


